package com.lp.syn_test;

import java.util.concurrent.atomic.AtomicInteger;

public class SychronizedMethodTest implements Runnable{
    private static int i = 0;//共享资源
    private static AtomicInteger ai = new AtomicInteger(0);//共享资源
    public static void main(String[] args) throws InterruptedException {
        /**
         * 使用synchronized修饰方法
         */
//        com.lp.syn_test.SychronizedTest st = new com.lp.syn_test.SychronizedTest();
//        Thread t1 = new Thread(st);
//        Thread t2 = new Thread(st);
//        t1.start();
//        t2.start();
        //join()的作用让调用该方法的线程在执行完run()方法后，再执行join()方法后面的代码。
//        t1.join();
//        t2.join();
//        System.out.println(i);
        /**
         * synchronized修饰方法实际锁定的实施例对象，不同的对象仍然不能保证线程安全
         */
        SychronizedMethodTest st1 = new SychronizedMethodTest();
        SychronizedMethodTest st2 = new SychronizedMethodTest();
        Thread t1 = new Thread(st1);
        Thread t2 = new Thread(st2);
        t1.start();
        t2.start();
        //join()的作用让调用该方法的线程在执行完run()方法后，再执行join()方法后面的代码。
        t1.join();
        t2.join();
        System.out.println(i);
        /**
         * 利用原子类，可以不使用synchronized实现线程安全
         */
//        com.lp.syn_test.SychronizedTest st = new com.lp.syn_test.SychronizedTest();
//        Thread t1 = new Thread(st);
//        Thread t2 = new Thread(st);
//        t1.start();
//        t2.start();
//        //join()的作用让调用该方法的线程在执行完run()方法后，再执行join()方法后面的代码。
//        t1.join();
//        t2.join();
//        System.out.println(ai);
    }

    /**
     * 上述代码中，我们开启两个线程操作同一个共享资源即变量i，由于i++;操作并不具备原子性，该操作是先读取值，然后写回一个新值，相当于原来的值加上1，分两步完成，
     * 如果第二个线程在第一个线程读取旧值和写回新值期间读取i的域值，那么第二个线程就会与第一个线程一起看到同一个值，并执行相同值的加1操作，这也就造成了线程安全失败，
     * 因此对于increase方法必须使用synchronized修饰，以便保证线程安全。
     */
    /**
     * synchronized 修饰实例方法
     */
    public synchronized void increase(){
        i++;
    }
    /**
     * 通过使用原子类也可以保证线程安全
     */
//    public void increase(){
//        ai.incrementAndGet();
//    }
    @Override
    public void run() {
        for(int j=0;j<1000000;j++){
            increase();
        }
    }
}
